##########################################
## Copyright 2012-2013 Ceruti Francesco & contributors
##
## This file is part of LiSP (Linux Show Player).
##########################################

from PyQt4 import QtCore, QtGui

from lisp.core.plugin import Plugin
from lisp.core.timing import MediaTime
from lisp.core.media import Media

from .p_actions import Pause, Play, Seek, Stop, ToSpeed, ToVolume, PAction
from .p_ui import ProgrammingUI


class Programming(Plugin):

    PLUGIN_NAME = "Programming"

    SYNTAX = {Pause.ID: Pause,
              Play.ID: Play,
              Seek.ID: Seek,
              Stop.ID: Stop,
              ToSpeed.ID: ToSpeed,
              ToVolume.ID: ToVolume
              }

    def __init__(self, main):
        self.collector = main.collector
        self.main = main

        self.eventProgrammingAction = QtGui.QAction(None, triggered=lambda: self.showUI(True))
        self.eventProgrammingAction.setText("Event programming")
        self.stepProgrammingAction = QtGui.QAction(None, triggered=lambda: self.showUI(False))
        self.stepProgrammingAction.setText("Step programming")

        self.programs = []
        self.reset()

    def showUI(self, timeMode):
        contextMedia = self.layout.contextMenuMedia()
        if(contextMedia.state != Media.NONE):
            pUI = ProgrammingUI(contextMedia, timeMode)
            if(timeMode and contextMedia in self.media):
                pUI.setActions(self.programs[self.media.index(contextMedia)].actions)
            elif(not timeMode):
                pUI.setActions(self.layout.mediaActionsList(contextMedia))
            pUI.exec_()

            if(pUI.result() == pUI.Accepted):
                program = pUI.getProgramStr()
                if(timeMode):
                    contextMedia.conf['eprogramming'] = program
                    if(contextMedia in self.media):
                        if(program != ''):
                            self.programs[self.media.index(contextMedia)].setActions(pUI.getActions())
                        else:
                            self.programs.pop(self.media.index(contextMedia)).destroy()
                            self.media.remove(contextMedia)
                    elif(program != ''):
                        p = Program(pUI.getActions(), contextMedia)
                        self.programs.append(p)
                        self.media.append(contextMedia)
                else:
                    contextMedia.conf['sprogramming'] = program
                    if(program != ''):
                        self.layout.setMediaActionsList(contextMedia, pUI.getActions())
                    else:
                        contextMedia.conf.pop('sprogramming')

    def reload(self):
        for media in self.collector.media:
            if(media.state != Media.NONE):
                if('eprogramming' in media.conf):
                    if(media in self.media):
                        self.programs[media].setActions(self.parseEvent(media))
                    else:
                        p = Program(self.parseEvent(media), media)
                        self.programs.append(p)
                        self.media.append(media)
                if('sprogramming' in media.conf):
                    self.layout.setMediaActionsList(media, self.parseStep(media))

    def reset(self):
        self.layout = self.main.collectorUi
        self.layout.registerContextAction(self.eventProgrammingAction, True)
        self.layout.registerContextAction(self.stepProgrammingAction, False, True)

        for program in self.programs:
            program.destroy()

        self.media = []
        self.programs = []

    def parseStep(self, media):
        program = media.conf['sprogramming'].split(';')
        return self.parse(program, media)

    def parseEvent(self, media):
        program = media.conf['eprogramming'].split(';')
        return sorted(self.parse(program, media), key=PAction.getTime)

    def parse(self, program, media):
        actions = []
        for p in program:
            action = Programming.SYNTAX[p.split(':')[1]](media)
            action.fromString(p)
            actions.append(action)
        return actions


class Program:

    def __init__(self, actions, media):
        self.media = media
        self.actions = actions

        self.time = MediaTime(media, wait=0.25)
        self.index = 0

        self.time.progress.connect(self.onProgress, QtCore.Qt.QueuedConnection)
        self.proxy = lambda m: self.reset()
        self.media.onStopped.connect(self.proxy)
        self.media.onEndOfStream.connect(self.proxy)
        self.media.onError.connect(self.proxy)

    def onProgress(self, current):
        if(self.index < len(self.actions)):
            if(current >= self.actions[self.index].time):
                self._exec()

    def _exec(self):
        self.actions[self.index].exec_()
        self.index += 1
        if(self.index != len(self.actions)):
            if(self.actions[self.index - 1].time == self.actions[self.index].time):
                self._exec()

    def reset(self):
        self.index = 0

    def setActions(self, actions):
        self.reset()
        self.actions = actions

    def destroy(self):
        self.time.progress.disconnect(self.onProgress)
        self.media.onStopped.disconnect(self.proxy)
        self.media.onEndOfStream.disconnect(self.proxy)
        self.media.onError.disconnect(self.proxy)
